﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO.Ports;
using System.Threading;

/// <summary>
/// 电阻测试任务：仅测 1#、2# 通道双向低电阻
/// </summary>
public class MeasurementTask
{
    private readonly SerialPort _serialPort; // 串口对象，用于与硬件设备通信
    private readonly Action<byte, double> _callback; // 回调方法，用于在测量完成后处理结果
    private readonly List<byte> _rxBuf; // 接收缓冲区，用于存储从串口接收到的数据
    private readonly AutoResetEvent _evt; // 自动重置事件，用于通知数据已接收
    private const int TIMEOUT = 2000; // 等待结果的超时时间，单位为毫秒

    public MeasurementTask(SerialPort sp, Action<byte, double> cb, List<byte> buf, AutoResetEvent evt)
    {
        _serialPort = sp; // 初始化串口对象
        _callback = cb; // 初始化回调方法
        _rxBuf = buf; // 初始化接收缓冲区
        _evt = evt; // 初始化自动重置事件
    }

    public void Run()
    {
        // 测试 1# 通道的双向低电阻
        Measure(Dzc9RProtocol.CMD_CHANNEL_1, "1#通道双向低电阻");
        // 测试 2# 通道的双向低电阻
        Measure(Dzc9RProtocol.CMD_CHANNEL_2, "2#通道双向低电阻");
    }

    private void Measure(byte channelCmd, string desc)
    {
        Debug.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] 开始 {desc}"); // 输出开始测量的日志信息

        // 构建测量命令，目标设备地址为默认地址，命令类型为指定通道，参数为双向低电阻
        byte[] cmd = Dzc9RProtocol.BuildCommand(
            Dzc9RProtocol.DEVICE_ADDR_DEFAULT,
            channelCmd,
            Dzc9RProtocol.PARAM_BIDIR_LOW);

        // 根据协议要求，命令需要发送两次，间隔 180 毫秒
        for (int i = 0; i < 2; i++)
        {
            _serialPort.Write(cmd, 0, cmd.Length); // 通过串口发送命令
            Thread.Sleep(180); // 等待 180 毫秒
        }

        // 等待并获取测量结果
        double value = WaitResult(channelCmd);
        // 调用回调方法处理测量结果
        _callback?.Invoke(channelCmd, value);

        // 输出测量完成的日志信息，包括测量值
        Debug.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] {desc} 完成: {value:F4} Ω");
    }

    private double WaitResult(byte expectedCmd)
    {
        lock (_rxBuf) _rxBuf.Clear(); // 清空接收缓冲区
        var sw = Stopwatch.StartNew(); // 开始计时

        // 在超时时间内等待结果
        while (sw.ElapsedMilliseconds < TIMEOUT)
        {
            // 等待数据接收事件，每隔 50 毫秒检查一次
            if (_evt.WaitOne(50))
            {
                lock (_rxBuf)
                {
                    // 检查接收缓冲区是否有足够的数据
                    if (_rxBuf.Count >= Dzc9RProtocol.FRAME_LENGTH)
                    {
                        // 获取一个完整的帧数据
                        byte[] frame = _rxBuf.GetRange(0, Dzc9RProtocol.FRAME_LENGTH).ToArray();
                        // 验证帧校验和，以及帧中的设备地址、命令和响应类型是否符合预期
                        if (Dzc9RProtocol.VerifyChecksum(frame) &&
                            frame[6] == Dzc9RProtocol.DEVICE_ADDR_DEFAULT &&
                            frame[7] == expectedCmd &&
                            frame[5] == Dzc9RProtocol.RESP_BIDIR_LOW)
                        {
                            // 从接收缓冲区移除已解析的帧数据
                            _rxBuf.RemoveRange(0, Dzc9RProtocol.FRAME_LENGTH);
                            // 解析并返回双向低电阻的测量值
                            return Dzc9RProtocol.ParseBidirLowResistance(frame);
                        }
                    }
                }
            }
        }
        // 如果超时仍未收到有效结果，抛出超时异常
        throw new TimeoutException($"{expectedCmd} 通道读取超时");
    }
}
